import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import org.jdom.*;
import org.jdom.input.*;
import org.jdom.transform.*;
import org.jdom.output.*;
import org.jdom.filter.*;
import java.net.*;
import java.util.*;
import net.sf.saxon.*;

public class Read extends HttpServlet {
    private String defaultURL = "http://localhost:8080/Wiki/Server";
    private SAXBuilder b = new SAXBuilder();
    private Document servers = new Document();
    public void doGet(HttpServletRequest request, 
		      HttpServletResponse response)
	throws IOException, ServletException {
	PrintWriter out = response.getWriter();
	String word = htmlEscape(request.getParameter("word"));
	String wiki = htmlEscape(request.getParameter("wiki"));
	SAXBuilder b = new SAXBuilder();
	if(word==null) {
	    word="MainPage";
	    response.sendRedirect("Read?wiki=Recyclopedia&word=MainPage");
	    response.flushBuffer();
	}
	if(wiki==null) {
	    wiki="Recyclopedia";
	}
	response.setContentType("text/plain");

	String host = "localhost";
	String port = "8080";
	URL serverURL = new URL(defaultURL);
	try{
	    serverURL = getServerURL(wiki);
	}
	catch(Exception e){
	    out.print("[getServerURL:" + e + "]");
	    System.err.print(e);
	}
	
	Document contDoc = new Document();
	Document doc = new Document();
	try{
	    doc = b.build(serverURL + "?word=" + word);
	    File contFile = new File("webapps/Wiki/WEB-INF/source/WikiXML2XHTML.xsl");
	    contDoc = getXMLDocument(doc,contFile);
	    changeLink(contDoc,b,wiki,word);
	    changeLinkInEdit(contDoc,wiki,word);
	    insertWikiInLink(contDoc,wiki);
	    setWikiInGetForm(contDoc,wiki);
	    showWikiServer(contDoc,wiki);
	}
	catch(Exception e){
	    out.print(e);
	}
	finally{
	    XMLOutputter outputter = new XMLOutputter();
	    try{
		response.setContentType("text/html"); 
		outputter.output(contDoc,out);
	    }
	    catch(Exception e){
		out.print("[output-contDok:" + e + "]");
		response.sendRedirect("Edit?wiki=" + wiki + "&word="+word);
		System.err.print(e);
	    }
	    out.close();
	}
    }
    
    private URL getServerURL(String wiki) throws Exception{
	Document servDoc = b.build(new URL("http://kalashnikov.daimi.au.dk:8888/Wiki/Meta"));
	XMLOutputter xmlOutputter = new XMLOutputter();
	String urlString = defaultURL;
	Element rootElement = new Element("wiki");
	Element servRoot = servDoc.getRootElement();
	Iterator i = servDoc.getRootElement().getDescendants(new ElementFilter("server"));
	/**
	 * RootElement:
	 * <wiki>
	 *   <server host="" name="" port="">
	 *   <server host="" name="" port="">
	 *   . . . etc. en for hver server der matcher navnet. 
	 *   Hvis der er flere der matcher returneres den sidste.
	 */
	while(i.hasNext()){
	    Element ele = (Element)i.next();
	    if(ele.getAttributeValue("name").equals(wiki)){
		Element tmpServ = new Element("server");
		tmpServ.setAttribute("name",ele.getAttributeValue("name"));		
		tmpServ.setAttribute("host",ele.getAttributeValue("host"));		
		tmpServ.setAttribute("port",ele.getAttributeValue("port"));
		rootElement.addContent(tmpServ);
		urlString = "http://" + ele.getAttributeValue("host") + ":" + ele.getAttributeValue("port") + "/Wiki/Server";
	    }
	}
	this.servers = servRoot.getDocument();
	return new URL(urlString);
    }

    private Document getXMLDocument(Document doc, File xslFile) throws Exception {
	Transformer t = TransformerFactory.newInstance().newTransformer(new StreamSource(xslFile));
	JDOMSource inT = new JDOMSource(doc);
	JDOMResult outT = new JDOMResult();
	t.transform(inT,outT);
	return outT.getDocument();	
    }
    
    private void insertWikiInLink(Document d,String wiki) throws Exception{
	ArrayList<Element> eleList = new ArrayList<Element>();
	Iterator i = d.getDescendants(new ElementFilter("a"));
	while(i.hasNext()){
	    Element ele = (Element)i.next();
	    if(ele.getAttributeValue("href").contains("word=") && !ele.getAttributeValue("href").contains("?wiki=")){
		ele.setAttribute("href",ele.getAttributeValue("href") + "&wiki=" + wiki);
	    }
	}
    }
    
    private void changeLinkInEdit(Document d,String wiki,String word) throws Exception{
	ArrayList<Element> eleList = new ArrayList<Element>();
	Iterator i = d.getDescendants(new ElementFilter("a"));
	while(i.hasNext()){
	    Element ele = (Element)i.next();
	    if(ele.getAttributeValue("name") != null && 
	       ele.getAttributeValue("name").equals("test")){
		eleList.add(ele);
	    }
	}
	i = eleList.iterator();
	while(i.hasNext()){
	    Element ele = (Element)i.next();
	    ele.setAttribute("href","Edit?wiki="+wiki+"&word="+word);
	    ele.addContent("Edit");			    
	}
    } 
    
    
    private void serversInSelect(Document d){
	Iterator i = d.getDescendants(new ElementFilter("select"));
	Element ele = new Element("option");
	while(i.hasNext()){
	    ele = (Element)i.next();	    
	}
	Iterator j = servers.getDescendants(new ElementFilter("server"));
	while(j.hasNext()){
	    Element servEle = (Element)j.next();
	    Element option = new Element("option");
	    option.setAttribute("value",servEle.getAttributeValue("name"));
	    option.addContent(servEle.getAttributeValue("name"));
	    ele.addContent(option);
	}
    }
    
    private void changeLink(Document d, SAXBuilder b,String wiki,String word){
	Iterator i = d.getDescendants(new ElementFilter("div"));
	Element ele = new Element("div");
	while(i.hasNext()){
	    Element test = (Element)i.next();
	    if(test.getAttributeValue("name") != null && test.getAttributeValue("name").equals("wordlist")){
		ele = test; 
	    }
	}
	try{
	    Document words = b.build(getServerURL(wiki));
	    Iterator j = words.getDescendants(new ElementFilter("word"));
	    Element ul = new Element("ul");
	    while(j.hasNext()){
		Element wordEle = (Element)j.next();
		Element li = new Element("li");
		Element link = new Element("a");
		link.setAttribute("href","Read?wiki=" + wiki + "&word=" +wordEle.getText());
		link.addContent(wordEle.getText());
		li.addContent(link);
		ul.addContent(li);
	    }
	    ele.addContent(ul);    
	}
	catch(Exception e){
	    System.err.print(e);
	}
    }
    private void setWikiInGetForm(Document d,String wiki){
	ArrayList<Element> eleList = new ArrayList<Element>();
	Iterator i = d.getRootElement().getDescendants(new ElementFilter("form"));    
	while(i.hasNext()){
	    Element ele = (Element)i.next();
	    if(ele.getAttributeValue("method").equals("GET")){
		eleList.add(ele);
	    }
	}
	i = eleList.iterator();
	while(i.hasNext()){
	    Element ele = (Element)i.next();
	    Element wikiName = new Element("input");		    
	    wikiName.setAttribute("type","hidden");
	    wikiName.setAttribute("value",wiki);
	    wikiName.setAttribute("name","wiki");
	    ele.addContent(wikiName);
	}
    }
    private void showWikiServer(Document d, String wiki){
	Iterator i = d.getRootElement().getDescendants(new ElementFilter("div"));  
	Element ele = new Element("div");
	while(i.hasNext()){
	    Element tempEle = (Element)i.next();
	    if(tempEle.getAttributeValue("name") != null && tempEle.getAttributeValue("name").equals("wikiserver")){
		ele = tempEle;
	    }
	}
	ele.addContent(wiki + "-");
    }
    private String htmlEscape(String s){
	if(s == null)
	    return null;
	StringBuffer b = new StringBuffer();
	for(int i= 0 ; i<s.length(); i++){
	    char c= s.charAt(i);
	    switch(c){
	    case '<': b.append("&lt;"); break;
	    case '>': b.append("&gt;"); break;
	    case '"': b.append("&quot;"); break;
	    case '\'': b.append("&apos;"); break;
	    case '&': b.append("&amp;"); break;
	    default :b.append(c);
	    }
	}
	return b.toString();
    }
}
    
